// synchronize to period T=1 measure
1::second => dur T;
T - (now % T) => now;

// define scales
[0, 2, 4, 5, 7, 9, 11] @=> int maj[];
[0, 2, 3, 5, 7, 8, 10] @=> int min[];
[0, 3, 5, 7, 10] @=> int pent[];
[0, 2, 4, 7, 9] @=> int pleasant[];

[ maj, min, pent, pleasant ] @=> int scales[][];

[ 2, 4, 6 ] @=> int interval[];

[ 0, 3, 1, 3 ] @=> int meas1[];
[ 3, 0, 1, 3 ] @=> int meas2[];
//[ 0, 4, 5, 0 ] @=> int meas3[];

[ meas1, meas2] @=> int measures[][];

// define instruments
SinOsc bass => dac;
.1 => bass.gain;

SinOsc s => JCRev rev_s => dac;  // voice
.07 => s.gain;
.25 => rev_s.mix;

SinOsc v => JCRev rev_v => dac;  // voice2
.07 => v.gain;
.25 => rev_v.mix;

Bowed a => dac;
Bowed b => dac;
.35 => a.gain;
.3 => b.gain;
//.25 => rev_chord.mix;
//.5 => chord.gain;


fun void genBass(int key, int bars, int note) {
  Std.mtof(key) => bass.freq;
  for (0 => int i; i < note * bars; i++) {
    Std.rand2f(.3, .4) => bass.gain;
    (1.0/note)::T => now;
  }
}

fun void genBackground(int key, int bars) {
  // play V + I
  Std.mtof(key) => a.freq;
  Std.mtof(key+7) => b.freq;
  0.7 => a.noteOn;
  0.7 => b.noteOn;
  bars::T=>now;
  0.3 => a.noteOff;
  0.3 => b.noteOff;
}

// key: 60 = middle C, +12 per octave
// note: 4 = quarter note, 8 = eighth note
fun void genVoice(int key, int bars, int note, int set[]) {
  for (0 => int i; i < note * bars; i++) {
    Std.rand2f(.06, .09) => s.gain;
    0 => s.phase;
	
	Std.rand2f(.06, .09) => v.gain;
    0 => v.phase;
	
	Std.rand2(0,3)*12 => int octave;
    //  base key +      note           +     octave
	
	for (0 => int j; j < measures.cap(); j++) {
		for (0 => int i; i < measures[j].cap(); i++) {
			Std.mtof(key + set[measures[j][i]] + octave) => s.freq;
			findInterval(key + set[measures[j][i]] + octave, set) => v.freq;
			if (Std.randf() > 0.5)
				2*(1.0/note)::T => now;
			else
				(1.0/note)::T => now;
		}
	}
		
}
}


fun float findInterval(int noteIndex, int set[]) {
	interval[Std.rand2(0,interval.cap()-1)] => int chosen;
	noteIndex+chosen => int currentIndex;
	1 => int multiplier;
	while (currentIndex > set.cap()-1) {
		multiplier + 1 => multiplier;
		currentIndex - set.cap() + 1 => currentIndex;
	}
	return Std.mtof(set[currentIndex]+60);
}

fun int[] setSignature(int in) {
	if (in < 2) return min;
	else if (in < 4) return pent;
	else return maj;
}

ConsoleInput in;

while (true) {
	in.prompt("enter:");
	Std.atoi(in.getLine()) => int input;
  spork ~ genBass(36+input, 1, 8);
  spork ~ genVoice(60+input, 1, 8, setSignature(input));
  spork ~ genBackground(60+input, 1);
  1::T => now;
}
